/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** *****************************************************************************************************
 * \file     Uart.c                                                                                     *
 * \brief    MCAL Uart Driver                                                                           *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2024/10/29     <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/

#include "Uart.h"
#include "Uart_Ip.h"
#include "Det.h"
#include "Mcal.h"
#include "Uart_Fault.h"

/********************************************************************************************************
 *                                  Global Variable Declarations                                        *
 *******************************************************************************************************/
#if (STD_ON == UART_CORE0_ENABLE)
#define UART_CORE0_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
static Uart_HandlerType Uart_HandlerCore0 LOCATE_ALIGNED(UART_CACHE_LINE);
#define UART_CORE0_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
#endif /* #if (STD_ON == UART_CORE0_ENABLE) */

#if (STD_ON == UART_CORE1_ENABLE)
#define UART_CORE1_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
static Uart_HandlerType Uart_HandlerCore1 LOCATE_ALIGNED(UART_CACHE_LINE);
#define UART_CORE1_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
#endif /* #if (STD_ON == UART_CORE1_ENABLE) */

#if (STD_ON == UART_CORE2_ENABLE)
#define UART_CORE2_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
static Uart_HandlerType Uart_HandlerCore2 LOCATE_ALIGNED(UART_CACHE_LINE);
#define UART_CORE2_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
#endif /* #if (STD_ON == UART_CORE2_ENABLE) */

#if (STD_ON == UART_CORE3_ENABLE)
#define UART_CORE3_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
static Uart_HandlerType Uart_HandlerCore3 LOCATE_ALIGNED(UART_CACHE_LINE);
#define UART_CORE3_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Uart_MemMap.h"
#endif /* #if (STD_ON == UART_CORE3_ENABLE) */

#define UART_START_SEC_CONST_UNSPECIFIED
#include "Uart_MemMap.h"
const uint8 channelMaxIdxOnCore[CPU_MAX_CORE_NUMBER] = {
    UART_CHANNEL_MAX_IDX_CORE0,
    UART_CHANNEL_MAX_IDX_CORE1,
    UART_CHANNEL_MAX_IDX_CORE2,
    UART_CHANNEL_MAX_IDX_CORE3,
};

Uart_HandlerType * const Uart_Handler[CPU_MAX_CORE_NUMBER] =
{
#if (STD_ON == UART_CORE0_ENABLE)
    &Uart_HandlerCore0,
#else /* #if (STD_ON == UART_CORE0_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == UART_CORE0_ENABLE) */

#if (STD_ON == UART_CORE1_ENABLE)
    &Uart_HandlerCore1,
#else /* #if (STD_ON == UART_CORE1_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == UART_CORE1_ENABLE) */

#if (STD_ON == UART_CORE2_ENABLE)
    &Uart_HandlerCore2,
#else /* #if (STD_ON == UART_CORE2_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == UART_CORE2_ENABLE) */

#if (STD_ON == UART_CORE3_ENABLE)
    &Uart_HandlerCore3,
#else /* #if (STD_ON == UART_CORE3_ENABLE) */
    NULL_PTR,
#endif /* #if (STD_ON == UART_CORE3_ENABLE) */
};
#define UART_STOP_SEC_CONST_UNSPECIFIED
#include "Uart_MemMap.h"

#define UART_START_SEC_CODE
#include "Uart_MemMap.h"
/********************************************************************************************************
 *                                  Private Function Declarations                                       *
 *******************************************************************************************************/
static Std_ReturnType Uart_ChannelDetCheck(uint8 Channel)
{
    Std_ReturnType errorId = E_OK;
    uint8 coreId = Uart_GetCoreId();

    if (UART_UNINIT == Uart_Handler[coreId]->driverStatus)
    {
        errorId = UART_E_UNINIT;
    }
    else if (channelMaxIdxOnCore[coreId] < Channel)
    {
        errorId = UART_E_INVALID_CHANNEL;
    }
    else if (coreId != Uart_Handler[coreId]->config->channelConfigs[Channel].assignCoreId)
    {
        errorId = UART_E_ILLEGAL_RES_ACCESS;
    }
    else if (UART_AUTOBAUD_STATE_BUSY == Uart_Handler[coreId]->state[Channel].autoBaudState)
    {
        errorId = UART_E_AUOTOBAUD_BUSY;
    }

    return errorId;
}

/********************************************************************************************************
 *                                  Global Function Declarations                                        *
 *******************************************************************************************************/
void Uart_Init(const Uart_ConfigType * Config)
{
    uint8 channelIdx = 0U;
    Std_ReturnType errorId = E_OK;
    uint8 coreId = Uart_GetCoreId();

    if ((NULL_PTR == Config) ||
        (NULL_PTR == Uart_Handler[coreId]))
    {
        /* Invalid pointer */
        errorId = UART_E_PARAM_POINTER;
    }
    else if (UART_INIT == Uart_Handler[coreId]->driverStatus)
    {
        /* already init */
        errorId = UART_E_ALREADY_INITIALIZED;
    }
    else
    {
        Uart_Handler[coreId]->config = Config;

        for (channelIdx = 0U; channelIdx <= channelMaxIdxOnCore[coreId]; channelIdx++)
        {
            UartHook_Uart_Init_Skip();
            if (coreId == Uart_Handler[coreId]->config->channelConfigs[channelIdx].assignCoreId)
            {
                errorId = Uart_Ip_Init(channelIdx);
                if (E_OK != errorId)
                {
                    Uart_Handler[coreId]->config = NULL_PTR;
                    break;
                }
            }
        }
    }

    if (E_OK != errorId)
    {
#if (STD_ON == UART_DEV_ERROR_DETECT)
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_INIT_SID,
                                errorId);
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */
    }
    else
    {
        Uart_Handler[coreId]->driverStatus = UART_INIT;
    }

}

void Uart_Deinit(void)
{
    uint8 channelIdx;
    boolean channelIdleStatus = TRUE;
    Std_ReturnType errorId;
    uint8 coreId = Uart_GetCoreId();

    if (UART_INIT != Uart_Handler[coreId]->driverStatus)
    {
        errorId = UART_E_UNINIT;
    }
    else
    {
        for (channelIdx = 0U; channelIdx <= channelMaxIdxOnCore[coreId]; channelIdx++)
        {
            UartHook_Uart_Deinit_Skip_Step1();
            if (coreId == Uart_Handler[coreId]->config->channelConfigs[channelIdx].assignCoreId)
            {
                if ((UART_STATUS_BUSY == Uart_Ip_GetTransmitStatus(channelIdx, NULL_PTR)) ||
                    (UART_STATUS_BUSY == Uart_Ip_GetReceiveStatus(channelIdx, NULL_PTR)))
                {
                    channelIdleStatus = FALSE;
                    break;
                }
            }
        }

        if (TRUE == channelIdleStatus)
        {
            for (channelIdx = 0U; channelIdx <= channelMaxIdxOnCore[coreId]; channelIdx++)
            {
                UartHook_Uart_Deinit_Skip_Step2();
                if (coreId == Uart_Handler[coreId]->config->channelConfigs[channelIdx].assignCoreId)
                {
                    Uart_Ip_Deinit(channelIdx);
                }
            }

            Uart_Handler[coreId]->config = NULL_PTR;
            UartHook_Uart_Deinit_Skip_Step3();
            Uart_Handler[coreId]->driverStatus = UART_UNINIT;
            errorId = E_OK;
        }
        else
        {
            errorId = UART_E_CHANNEL_BUSY;
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
            (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_DEINIT_SID,
                                    errorId);
    }
#else /** #if (STD_ON == UART_DEV_ERROR_DETECT) */
    UART_DUMMY_STATE(errorId);
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

}

Std_ReturnType Uart_SetBaudrate(uint8 Channel, Uart_BaudrateType Baudrate)
{
    Std_ReturnType errorId;

    if (0U == Baudrate)
    {
        /* invalid baudrate */
        errorId = UART_E_INVALID_BAUDRATE;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);
    }

    if ((UART_E_AUOTOBAUD_BUSY == errorId) || (E_OK == errorId))
    {
        errorId = Uart_Ip_SetBaudrate(Channel, Baudrate);
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_SET_BAUDRATE_SID,
                                errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

Std_ReturnType Uart_GetBaudrate(uint8 Channel, Uart_BaudrateType * Baudrate)
{
    Std_ReturnType errorId;

    if (NULL_PTR == Baudrate)
    {
        /* invalid pointer */
        errorId = UART_E_PARAM_POINTER;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);
    }

    if (E_OK != errorId)
    {
#if (STD_ON == UART_DEV_ERROR_DETECT)
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_GET_BAUDRATE_SID,
                                    errorId);
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */
    }
    else
    {
        Uart_Ip_GetBaudrate(Channel, Baudrate);
        errorId = E_OK;
    }

    return errorId;
}

Std_ReturnType Uart_SyncSend(uint8 Channel, const uint8* Buffer, uint32 BufferSize, uint32 Timeout)
{
    Std_ReturnType tempReturn = E_NOT_OK;
    Std_ReturnType errorId;

    if (NULL_PTR == Buffer)
    {
        /* invalid pointer */
        errorId = UART_E_PARAM_POINTER;
    }
    else if (0U == BufferSize)
    {
        /* invalid parameter */
        errorId = UART_E_INVALID_PARAM;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);

        if (E_OK == errorId)
        {
            tempReturn = Uart_Ip_SyncSend(Channel, Buffer, BufferSize, Timeout);
            if (UART_STATUS_BUSY == tempReturn)
            {
                /* channel busy */
                errorId = UART_E_CHANNEL_BUSY;
            }
            else if (UART_STATUS_TIMEOUT == tempReturn)
            {
                /* send timeout */
                errorId = UART_E_SYNC_TRANSFER_TIMEOUT;
            }
            else
            {
                errorId = E_OK;
            }
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_SYNC_SEND_SID,
                                    errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

Std_ReturnType Uart_SyncReceive(uint8 Channel, uint8* Buffer, uint32 BufferSize, uint32 Timeout)
{
    Std_ReturnType tempReturn = E_NOT_OK;
    Std_ReturnType errorId;

    if (NULL_PTR == Buffer)
    {
        /* invalid pointer */
        errorId = UART_E_PARAM_POINTER;
    }
    else if (0U == BufferSize)
    {
        /* invalid parameter */
        errorId = UART_E_INVALID_PARAM;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);

        if (E_OK == errorId)
        {
            tempReturn = Uart_Ip_SyncReceive(Channel, Buffer, BufferSize, Timeout);
            if (UART_STATUS_BUSY == tempReturn)
            {
                /* channel busy */
                errorId = UART_E_CHANNEL_BUSY;
            }
            else if (UART_STATUS_TIMEOUT == tempReturn)
            {
                /* receive timeout */
                errorId = UART_E_SYNC_TRANSFER_TIMEOUT;
            }
            else if (UART_STATUS_SUCCESS != tempReturn)
            {
                errorId = UART_E_SYNC_TRANSFER_ERR;
            }
            else
            {
                errorId = E_OK;
            }
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_SYNC_RECEIVE_SID,
                                    errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

Std_ReturnType Uart_AsyncSend(uint8 Channel, const uint8* Buffer, uint32 BufferSize)
{
    Std_ReturnType tempReturn = E_NOT_OK;
    Std_ReturnType errorId;

    if (NULL_PTR == Buffer)
    {
        /* invalid pointer */
        errorId = UART_E_PARAM_POINTER;
    }
    else if (0U == BufferSize)
    {
        /* invalid parameter */
        errorId = UART_E_INVALID_PARAM;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);

        if (E_OK == errorId)
        {
            tempReturn = Uart_Ip_AsyncSend(Channel, Buffer, BufferSize);
            if (UART_STATUS_BUSY == tempReturn)
            {
                /* channel busy */
                errorId = UART_E_CHANNEL_BUSY;
            }
            else
            {
                errorId = E_OK;
            }
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_ASYNC_SEND_SID,
                                    errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

Std_ReturnType Uart_AsyncReceive(uint8 Channel, uint8* Buffer, uint32 BufferSize)
{
    Std_ReturnType tempReturn = E_NOT_OK;
    Std_ReturnType errorId;

    if (NULL_PTR == Buffer)
    {
        /* invalid pointer */
        errorId = UART_E_PARAM_POINTER;
    }
    else if (0U == BufferSize)
    {
        /* invalid parameter */
        errorId = UART_E_INVALID_PARAM;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);

        if (E_OK == errorId)
        {
            tempReturn = Uart_Ip_AsyncReceive(Channel, Buffer, BufferSize);
            if (UART_STATUS_BUSY == tempReturn)
            {
                /* channel busy */
                errorId = UART_E_CHANNEL_BUSY;
            }
            else
            {
                errorId = E_OK;
            }
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_ASYNC_RECEIVE_SID,
                                    errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

Std_ReturnType Uart_StartRealTimeRecv(uint8 Channel)
{
    Std_ReturnType tempReturn = E_NOT_OK;
    Std_ReturnType errorId;

    errorId = Uart_ChannelDetCheck(Channel);

    if (E_OK == errorId)
    {
        tempReturn = Uart_Ip_StartRealTimeRecv(Channel);
        if (UART_STATUS_BUSY == tempReturn)
        {
            /* channel busy */
            errorId = UART_E_CHANNEL_BUSY;
        }
        else if (UART_STATUS_TIMEOUT == tempReturn)
        {
            /* init timeout */
            errorId = UART_E_TIMEOUT;
        }
        else
        {
            errorId = E_OK;
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_START_REAL_TIME_RECEIVE_SID,
                                    errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

Std_ReturnType Uart_StopRealTimeRecv(uint8 Channel)
{
    Std_ReturnType tempReturn = E_NOT_OK;
    Std_ReturnType errorId;

    errorId = Uart_ChannelDetCheck(Channel);

    if (E_OK == errorId)
    {
        tempReturn = Uart_Ip_StopRealTimeRecv(Channel);
        if (UART_STATUS_STOP_REALTIME_RECV_FAIL == tempReturn)
        {
            /* without call start realtime receive */
            errorId = UART_E_STOP_REALTIME_RECV_FAILED;
        }
        else if (UART_STATUS_TIMEOUT == tempReturn)
        {
            /* init timeout */
            errorId = UART_E_TIMEOUT;
        }
        else
        {
            errorId = E_OK;
        }
    }

#if (STD_ON == UART_DEV_ERROR_DETECT)
    if (E_OK != errorId)
    {
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_STOP_REAL_TIME_RECEIVE_SID,
                                    errorId);
    }
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */

    return errorId;
}

void Uart_Abort(uint8 Channel, Uart_DataDirectionType DirectionType)
{
    Std_ReturnType errorId;

    if ((UART_SEND != DirectionType) &&
             (UART_RECEIVE != DirectionType))
    {
        /* invalid direction type */
        errorId = UART_E_DIRECTION_TYPE;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);
    }

    if (E_OK != errorId)
    {
#if (STD_ON == UART_DEV_ERROR_DETECT)
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_ABORT_SID,
                                    errorId);
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */
    }
    else
    {
        if (UART_SEND == DirectionType)
        {
            Uart_Ip_AbortSendingData(Channel);
        }
        else
        {
            Uart_Ip_AbortReceivingData(Channel);
        }
    }

}

Uart_StatusType Uart_GetStatus(uint8 Channel, uint32 *BytesRemaining, Uart_DataDirectionType DirectionType)
{
    Uart_StatusType returnValue = UART_STATUS_ERROR;
    Std_ReturnType errorId;

    if ((UART_SEND != DirectionType) &&
        (UART_RECEIVE != DirectionType))
    {
        /* invalid direction type */
        errorId = UART_E_DIRECTION_TYPE;
    }
    else
    {
        errorId = Uart_ChannelDetCheck(Channel);
    }

    if (E_OK != errorId)
    {
#if (STD_ON == UART_DEV_ERROR_DETECT)
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_GET_STATUS_SID,
                                    errorId);
#endif /** #if (STD_ON == UART_DEV_ERROR_DETECT) */
    }
    else
    {
        if (UART_SEND == DirectionType)
        {
            returnValue = Uart_Ip_GetTransmitStatus(Channel, BytesRemaining);
        }
        else
        {
            returnValue = Uart_Ip_GetReceiveStatus(Channel, BytesRemaining);
        }
    }

    return returnValue;
}

void Uart_GetVersionInfo(Std_VersionInfoType * versioninfo)
{
    if (NULL_PTR == versioninfo)
    {
#if(UART_DEV_ERROR_DETECT == STD_ON)
        (void)Det_ReportError(UART_MODULE_ID, UART_INSTANCE_ID, UART_GET_VERSION_INFO_SID,
                              UART_E_PARAM_POINTER);
#endif
    }
    else
    {
        versioninfo->vendorID = UART_VENDOR_ID;
        versioninfo->moduleID = UART_MODULE_ID;
        versioninfo->sw_major_version = UART_SW_MAJOR_VERSION;
        versioninfo->sw_minor_version = UART_SW_MINOR_VERSION;
        versioninfo->sw_patch_version = UART_SW_PATCH_VERSION;
    }
}

#define UART_STOP_SEC_CODE
#include "Uart_MemMap.h"

#ifdef __cplusplus
}
#endif

/* End of file */
